.global com_call
com_call:
push %ebp
mov %esp, %ebp
#save ebx ecx edx
push %ebx
push %ecx
push %edx #&i = ebp-0x10

sub $0x4,%esp
mov 0x8(%ebp), %ebx #get arg0, ebx : a pointer to PARAM_INFO
mov (%ebx), %ecx    #ecx = param_info.fn

#check if param_info.param_cnt < 1, then directly call the func
movl 0x4(%ebx),%eax #eax=param_info.param_cnt
cmpl $0x1, %eax
jl call_com_fn

#for start, trans the param by stack
movl $0x0, -0x10(%ebp) #i = 0
mov 0x8(%ebx), %edx    #edx=param_info.params_addr
mov 0x4(%ebx), %eax
sub $0x1, %eax
lea 0x0(%edx, %eax, 4), %edx #edx=&param_info.params_addr[len-1]
jmp i_check

for_do:
mov (%edx), %eax
push %eax
subl $0x4, %edx         #edx -= 4
addl $0x01, -0x10(%ebp) #++i

i_check:
movl 0x4(%ebx), %eax
cmpl %eax, -0x10(%ebp)  #i - param_info.param_cnt
jl for_do
#for end

call_com_fn:
call *%ecx

#verify esp pointer
movl 0x4(%ebx), %edx   #edx=param_info.param_cnt
addl $0x1, %edx        #with instruction[sub $0x4,esp]
lea 0x0(%esp, %edx, 4), %esp

#recover edx ecx ebx register
pop %edx
pop %ecx
pop %ebx
leave
ret
